import Foundation

// 游戏结束原因
public enum GameOverReason: Int {
    case LOST           // 失败
    case RIVAL_ADMIT    // 自己认输
    case SELF_ADMIT     // 对手认输
    case WON            // 胜利
}

// 协议
public class GomokuProtocol: NSObject, NSCoding {
    public static let SERVER_IP = "192.168.1.222"   // 服务器 IP 地址
    public static let SERVER_PORT: UInt16 = 10000   // 服务器端口号

    // 协议类型
    public enum _Type: Int {
        case FIND_USERS     // 寻找其它用户
        case GAME_OVER      // 游戏结束
        case INVITE_REQUEST // 挑战请求
        case INVITE_RESULT  // 挑战结果
        case LOGON          // 登录
        case PUT_PIECE      // 放置棋子
        case QUIT_GAME      // 退出游戏
    }

    public let mType: _Type         // 类型
    public let mUsername: String?   // 用户名
    
    /**
     * 构造方法。
     */
    public override init() {
        mType = .FIND_USERS
        mUsername = ""
    }
    
    /**
     * 构造方法。
     * @param type      类型
     * @param username  用户名
     */
    public init(_ type: _Type, username: String) {
        mType = type
        mUsername = username
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mType = GomokuProtocol._Type(rawValue: coder.decodeInteger(forKey: "mType"))!
        mUsername = coder.decodeObject(forKey: "mUsername") as? String
    }
    
    /**
     * 归档，即将协议转换为字节数组。
     * @param pro   协议
     * @return 字节数组
     */
    public static func archive(_ pro: GomokuProtocol) -> [UInt8] {
        let data = try! NSKeyedArchiver.archivedData(withRootObject: pro, requiringSecureCoding: true)
        var bytes = [UInt8](repeating: 0, count: data.count)
        data.copyBytes(to: &bytes, count: data.count)
        
        return bytes
    }
    
    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public func encode(with aCoder: NSCoder) {
        aCoder.encode(mType.rawValue, forKey: "mType")
        aCoder.encode(mUsername, forKey: "mUsername")
    }
        
    /**
     * 解档，即将字节数组转换为协议。
     * @param bytes 字节数组
     * @param count 数组长度
     * @return 协议
     */
    public static func unArchive(_ bytes: UnsafeRawPointer, count: Int) -> GomokuProtocol {
        let data = Data(bytes: bytes, count: count)
        let pro = try! NSKeyedUnarchiver.__unarchivedObject(of: GomokuProtocol.self, from: data)
        return pro as! GomokuProtocol
    }
}

// 寻找用户请求
public class FindUsersRequest: GomokuProtocol, NSSecureCoding {
    /**
     * 构造方法。
     * @param username  用户名
     */
    public init(_ username: String) {
        super.init(.FIND_USERS, username: username)
    }
    
    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 寻找用户结果
public class FindUsersResult: GomokuProtocol, NSSecureCoding {
    public var mUsernameList: NSMutableArray?   // 用户名列表

    /**
     * 构造方法。
     * @param usernameList  用户名列表
     */
    public init(_ usernameList: NSMutableArray?) {
        mUsernameList = usernameList
        super.init(.FIND_USERS, username: "")
    }
    
    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mUsernameList = coder.decodeObject(of: NSMutableArray.self, forKey: "mUsernameList")
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mUsernameList, forKey: "mUsernameList")
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 游戏结束
public class GameOver: GomokuProtocol, NSSecureCoding {
    public let mReason: GameOverReason! // 结束原因

    /**
     * 构造方法。
     * @param reason    结束原因
     * @param rivalName 对手的名字
     */
    public init(_ reason: GameOverReason, rivalName: String) {
        mReason = reason
        super.init(.GAME_OVER, username: rivalName)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mReason = GameOverReason(rawValue: coder.decodeInteger(forKey: "mReason"))
        super.init(coder: coder)
    }
    
    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mReason.rawValue, forKey: "mReason")
    }
    
    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 挑战请求
public class InviteRequest: GomokuProtocol, NSSecureCoding {
    public let mRivalName: String   // 对手的名字

    /**
     * 构造方法。
     * @param rivalName 对手的名字
     * @param username  用户名
     */
    public init(_ rivalName: String, username: String) {
        mRivalName = rivalName
        super.init(.INVITE_REQUEST, username: username)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mRivalName = coder.decodeObject(forKey: "mRivalName") as! String
        super.init(coder: coder)
    }

    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mRivalName, forKey: "mRivalName")
    }
    
    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 挑战结果
public class InviteResult: GomokuProtocol, NSSecureCoding {
    public var mAccept: Bool        // 接受挑战则为 true，否则为 false
    public let mRivalName: String   // 对手的名字

    /**
     * 构造方法。
     * @param accept    接受挑战则为 true，否则为 false
     * @param rivalName 对手的名字
     * @param username  用户名
     */
    public init(_ accept: Bool, rivalName: String, username: String) {
        mAccept = accept
        mRivalName = rivalName
        super.init(.INVITE_RESULT, username: username)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mAccept = coder.decodeBool(forKey: "mAccept")
        mRivalName = coder.decodeObject(forKey: "mRivalName") as! String
        super.init(coder: coder)
    }
        
    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mAccept, forKey: "mAccept")
        aCoder.encode(mRivalName, forKey: "mRivalName")
    }
    
    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 登录请求
public class LogonRequest: GomokuProtocol, NSSecureCoding {
    /**
     * 构造方法。
     * @param username  用户名
     */
    public init(_ username: String) {
        super.init(.LOGON, username: username)
    }
    
    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 登录结果
public class LogonResult: GomokuProtocol, NSSecureCoding {
    /**
     * 构造方法。
     * @param username  用户名
     */
    public init(_ username: String) {
        super.init(.LOGON, username: username)
    }
    
    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 放置棋子
public class PutPiece: GomokuProtocol, NSSecureCoding {
    public var mX: Int  // x 坐标（窗口坐标）
    public var mY: Int  // y 坐标（窗口坐标）

    /**
     * 构造方法。
     * @param rivalName 对手的名字
     * @param x, y      棋子位置（窗口坐标）
     */
    public init(_ rivalName: String, x: Int, y: Int) {
        mX = x
        mY = y
        super.init(.PUT_PIECE, username: rivalName)
    }

    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        mX = Int(coder.decodeInt64(forKey: "mX"))
        mY = Int(coder.decodeInt64(forKey: "mY"))
        super.init(coder: coder)
    }
     
    /**
     * 协议编码。
     * @param aCoder    编码器
     */
    public override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(mX, forKey: "mX")
        aCoder.encode(mY, forKey: "mY")
    }
       
    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}

// 退出游戏
public class QuitGame: GomokuProtocol, NSSecureCoding {
    /**
     * 构造方法。
     * @param username  用户名
     */
    public init(_ username: String) {
        super.init(.QUIT_GAME, username: username)
    }
    
    /**
     * 必要的构造方法。
     * @param coder 解码器
     */
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    /**
     * 支持安全编码（必须加这个属性，否则解码会失败）。
     */
    public static var supportsSecureCoding: Bool {
        return true
    }
}
